package com.zwan.oam_rtc.utils;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class NumberPoolParser {

    private List<String> numberPool;
    private List<String> usedNumbers;
    private final Map<String, Long> usageTimestamps;
    private Random random;
    private String numberPoolConfig;
    private final Lock lock;
    private final ScheduledExecutorService scheduler;
    
    public NumberPoolParser(String numbers) {
        this.numberPoolConfig = numbers;
        this.numberPool = new ArrayList<>();
        this.usedNumbers = new ArrayList<>();
        this.usageTimestamps = new HashMap<>();
        this.usedNumbers = parseNumberPool();
        this.random = new Random();
        this.lock = new ReentrantLock();
        this.scheduler = Executors.newScheduledThreadPool(1);

        // Schedule the task to check for overdue numbers every minute
        scheduler.scheduleAtFixedRate(this::checkOverdueNumbers, 1, 1, TimeUnit.MINUTES);
    }

    public List<String> parseNumberPool() {
        String[] parts = numberPoolConfig.split(";");
        for (String part : parts) {
            if (part.contains("-")) {
                String[] range = part.split("-");
                String startStr = range[0];
                String endStr = range[1];

                // Check if start and end numbers have the same number of digits
                if (startStr.length() != endStr.length()) {
                    throw new IllegalArgumentException(
                            "Start and end numbers must have the same number of digits: " + part);
                }

                BigInteger start = new BigInteger(startStr);
                BigInteger end = new BigInteger(endStr);

                for (BigInteger i = start; i.compareTo(end) <= 0; i = i.add(BigInteger.ONE)) {
                    // Format the number with leading zeros
                    String number = String.format("%0" + startStr.length() + "d", i);
                    numberPool.add(formatNumber(number));
                }
            } else {
                numberPool.add(part);
            }
        }

        return numberPool;
    }

    private String formatNumber(String number) {
        if (number.startsWith("+86")) {
            // If the number already starts with +86, return it as is
            return number;
        } else if (number.startsWith("86")) {
            // If the number starts with 86, add the + prefix
            return "+" + number;
        } else if (number.startsWith("0")) {
            // Remove leading zeros and add +86 prefix
            number = number.replaceFirst("^0+", "");
            return "+86" + number;
        } else {
            // For all other cases, add +86 prefix
            return "+86" + number;
        }
    }

    public String getNumber() {
        lock.lock();
        try {
            if (numberPool.isEmpty()) {
                throw new IllegalStateException("无空闲号码");
            }
            int index = random.nextInt(numberPool.size());
            String selectedNumber = numberPool.remove(index);
            usedNumbers.add(selectedNumber);
            usageTimestamps.put(selectedNumber, System.currentTimeMillis());
            log.info(selectedNumber + " occupied");
            return selectedNumber;
        } finally {
            lock.unlock();
        }
    }

    public void returnNumber(String number) {
        lock.lock();
        try {
            if (usedNumbers.contains(number)) {
                usedNumbers.remove(number);
                numberPool.add(number);
                usageTimestamps.remove(number);
                log.info(number + " releaseed");
            } else {
                throw new IllegalArgumentException(number + " 号码未使用");
            }
        } finally {
            lock.unlock();
        }
    }

    private void checkOverdueNumbers() {
        long currentTime = System.currentTimeMillis();
        long overdueTime = 30 * 60 * 1000; // 30 minutes in milliseconds

        for (Map.Entry<String, Long> entry : usageTimestamps.entrySet()) {
            if (currentTime - entry.getValue() > overdueTime) {
                log.warn("Warning: Number " + entry.getKey() + " has not been returned for over 30 minutes.");
            }
        }
    }
}
